package com.zxy.fmmall.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sun.org.apache.bcel.internal.generic.NEW;
import com.zxy.fmmall.dao.OrderItemMapper;
import com.zxy.fmmall.dao.OrdersMapper;
import com.zxy.fmmall.dao.ProductSkuMapper;
import com.zxy.fmmall.dao.ShoppingCartMapper;
import com.zxy.fmmall.entity.OrderItem;
import com.zxy.fmmall.entity.Orders;
import com.zxy.fmmall.entity.ProductSku;
import com.zxy.fmmall.entity.ShoppingCartVo;
import com.zxy.fmmall.service.OrdersService;
import com.zxy.fmmall.utils.PageHelper;
import com.zxy.fmmall.vo.ResultVo;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class OrdersServiceImpl implements OrdersService {
    @Autowired
    private OrdersMapper ordersMapper;
    @Autowired
    private OrderItemMapper orderItemMapper;
    @Autowired
    private ShoppingCartMapper shoppingCartMapper;
    @Autowired
    private ProductSkuMapper productSkuMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedissonClient redissonClient;
    private Logger logger = LoggerFactory.getLogger(OrdersServiceImpl.class);

    @Override
    @Transactional
    public Map<String, String> addOrders(Orders orders, String cartId) {
        logger.info("增加订单");
        HashMap<String, String> map = null;
        // 查询购物车列表
        ArrayList<Integer> integers = new ArrayList<>();
        String[] split = cartId.split(",");
        for (String s : split) {
            integers.add(Integer.parseInt(s));
        }
        // 根据用户在购物车列表中选择的购物车记录id查询到对应的购物记录
        List<ShoppingCartVo> shoppingCartVos = shoppingCartMapper.listShoppingCartByCartId(integers);
        boolean isTrue = true;
        // 设置数组，为后面释放锁做准备 数组里是被锁住的id ["1","2","null"]
        String[] skuIds = new String[shoppingCartVos.size()];
        // 存储redis中的内容为后面验证是否是该线程的锁做准备
//        HashMap<String, String> values = new HashMap<>();

//        使用reisson
        HashMap<String, RLock> locks = new HashMap<>();
        for (int i = 0; i < shoppingCartVos.size(); i++) {
            ShoppingCartVo shoppingCartVo = shoppingCartVos.get(i);
            String skuId = shoppingCartVo.getSkuId();
//            String value = UUID.randomUUID().toString();
            boolean b = false;
            try {
//                Boolean sku = stringRedisTemplate.boundValueOps(skuId).setIfAbsent(value, 10, TimeUnit.MINUTES);
                RLock lock = redissonClient.getLock(skuId);
                b = lock.tryLock(10,3,TimeUnit.SECONDS);
                if (b) {
                    skuIds[i] = skuId;
//                    values.put(skuId, value);
                    locks.put(skuId,lock);
                }
//                isTrue = isTrue && sku;
                isTrue = isTrue && b;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        try {
            //相当于加锁
            if (isTrue) {
                // 比较库存，当第一次查询购物车记录之后，在加索成功之前，可能被其他的并发线程修改库存
                shoppingCartVos = shoppingCartMapper.listShoppingCartByCartId(integers);
                boolean isEnough = true;
                // 查询库存是否充足
                String untitled = "";
                for (ShoppingCartVo shoppingCartVo : shoppingCartVos) {
                    if (Integer.parseInt(shoppingCartVo.getCartNum()) > shoppingCartVo.getStock()) {
                        isEnough = false;
                        break;
                    }
                    untitled = untitled + shoppingCartVo.getProductName();
                }
                // 库存充足，进行  添加订单，保存快照，修改库存，删除购物车
                if (isEnough) {
                    // 生成订单id
                    //  保存订单
                    String orderId = UUID.randomUUID().toString().replace("-", "");
                    orders.setUntitled(untitled);
                    orders.setOrderId(orderId);
                    orders.setStatus("1");
                    orders.setCreateTime(new Date());
                    int insert = ordersMapper.insert(orders);

                    if (insert > 0) {
                        // 生成订单快照
                        for (ShoppingCartVo sc : shoppingCartVos) {
                            OrderItem orderItem = new OrderItem();
                            String itemId = System.currentTimeMillis() + "" + (new Random().nextInt(8999) + 1000);
                            orderItem.setItemId(itemId);
                            orderItem.setOrderId(orderId);
                            orderItem.setProductId(sc.getProductId());
                            orderItem.setProductImg(sc.getUrl());
                            orderItem.setSkuId(sc.getSkuId());
                            orderItem.setSkuName(sc.getSkuName());
                            orderItem.setProductPrice(sc.getProductPrice());
                            orderItem.setProductName(sc.getProductName());
                            int cnum = Integer.parseInt(sc.getCartNum());
                            orderItem.setBuyCounts(cnum);
                            orderItem.setTotalAmount(BigDecimal.valueOf(sc.getSellPrice() * cnum));
                            orderItem.setBasketDate(new Date());
                            orderItem.setBuyTime(new Date());
                            orderItem.setIsComment(0);
                            orderItemMapper.insert(orderItem);
                        }
                        // 更新库存
                        for (ShoppingCartVo sc : shoppingCartVos) {
                            String skuId = sc.getSkuId();
                            int newStoken = sc.getStock() - Integer.parseInt(sc.getCartNum());
                            ProductSku productSku = new ProductSku();
                            productSku.setSkuId(skuId);
                            productSku.setStock(newStoken);
                            int k = productSkuMapper.updateByPrimaryKeySelective(productSku);
                        }
                        // 删除购物车
                        for (Integer integer : integers) {
                            shoppingCartMapper.deleteByPrimaryKey(integer);
                        }

                        map = new HashMap<>();
                        map.put("orderId", orderId);
                        map.put("productNames", untitled);
                        System.out.println("map = " + map.get("productNames"));
                        System.out.println("map = " + map.get("orderId"));
                        return map;
                    }
                }
            }
        } catch (NumberFormatException e) {
            e.printStackTrace();
        } finally {
            //释放锁
            for (int i = 0; i < skuIds.length; i++) {
                String skuId = skuIds[i];
                if (skuIds != null && !"".equals(skuIds)) {
//                    // 释放锁之前，先查询当前的value
//                    String s = stringRedisTemplate.boundValueOps(skuId).get();
//                    //  如果从redis中获取 的值与生成的value是一至的，则表示此锁是当前线程的锁
//                    if (s != null && s.equals(values.get(skuId))) {
//                        stringRedisTemplate.delete(skuId);
//                    }
                    locks.get(skuId).unlock();
                    System.out.println("unlock ============= ");
                }
            }
        }
        return map;
    }

    @Override
    public int updateOrderStatus(String orderId, String status) {
        Orders orders = new Orders();
        orders.setStatus(status);
        orders.setOrderId(orderId);
        int i = ordersMapper.updateByPrimaryKeySelective(orders);
        return i;
    }

    @Override
    public ResultVo getOrderById(String orderId) {
        Orders orders = ordersMapper.selectByPrimaryKey(orderId);
        return ResultVo.ok().data("orderStatus", orders.getStatus()).message("success");
    }

    @Override
    @Transactional(isolation = Isolation.SERIALIZABLE)
    public void closeTimeOutJob(String orderId) {
        // b.修改当前订单：status = 6；已关闭 close_type = 1超时未支付
        Orders orders1 = new Orders();
        orders1.setCloseType(1);
        orders1.setOrderId(orderId);
        orders1.setStatus("6");
        ordersMapper.updateByPrimaryKeySelective(orders1);
        // c.还原库存，根据当前订单编号查询商品快照（skuid  buy_count）-->修改product_sku

        Example example1 = new Example(OrderItem.class);
        Example.Criteria criteria1 = example1.createCriteria();
        criteria1.andEqualTo("orderId", orderId);
        List<OrderItem> orderItems = orderItemMapper.selectByExample(example1);

        for (int j = 0; j < orderItems.size(); j++) {
            OrderItem orderItem = orderItems.get(j);
            // 还原库存
            ProductSku productSku = productSkuMapper.selectByPrimaryKey(orderItem.getSkuId());
            productSku.setStock(productSku.getStock() + orderItem.getBuyCounts());
            productSkuMapper.updateByPrimaryKey(productSku);
        }
    }

    @Override
    public ResultVo getOrderByUserId(String userId, String status, int pageNum, int limit) {
        int start = (pageNum - 1) * limit;
        List<Orders> list = ordersMapper.getOrderByUserId(userId, status, start, limit);
        PageHelper<Orders> pageHelper = new PageHelper<>();
        pageHelper.setList(list);
        Example example = new Example(Orders.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("userId", userId);
        if (status != null && !"".equals(status)) {
            criteria.andEqualTo("status", status);
        }
        int count = ordersMapper.selectCountByExample(example);
        pageHelper.setCount(count);
        int pageCount = count % limit == 0 ? count / limit : count / limit + 1;
        pageHelper.setPageCount(pageCount);
        return ResultVo.ok().data("pageHelper", pageHelper);
    }


}
